home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / hplip / base / models.py < prev    next >
Text File  |  2009-10-09  |  16KB  |  536 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # (c) Copyright 2003-2008 Hewlett-Packard Development Company, L.P.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18. #
  19. # Author: Don Welch
  20.  
  21. # Local
  22. from base.g import *
  23. from base import utils
  24.  
  25. # StdLib
  26. import os.path
  27. import re
  28. import glob
  29.  
  30. try:
  31.     import datetime
  32.     datetime_avail = True
  33. except ImportError:
  34.     datetime_avail = False
  35.     datetime = None
  36.  
  37.  
  38. pat_prod_num = re.compile("""(\d+)""", re.I)
  39.  
  40. TYPE_UNKNOWN = 0
  41. TYPE_STRING = 1
  42. TYPE_STR = 1
  43. TYPE_LIST = 2
  44. TYPE_BOOL = 3
  45. TYPE_INT = 4
  46. TYPE_HEX = 5
  47. TYPE_BITFIELD = 6
  48. TYPE_URI = TYPE_STR # (7) not used (yet)
  49. TYPE_DATE = 8  # format: mm/dd/yyyy
  50.  
  51.  
  52. TECH_CLASSES = [
  53.     "Undefined", # This will show an error (and its the default)
  54.     "Unsupported", # This is for unsupported models, and it will not show an error
  55.     "Postscript",
  56.     "DJGenericVIP",
  57.     #"PSB9100", not used on HPLIP
  58.     "LJMono",
  59.     "LJColor",
  60.     "LJFastRaster",
  61.     "LJJetReady",
  62.     "DJ350",
  63.     #"DJ400", not used on HPLIP
  64.     "DJ540",
  65.     "DJ600",
  66.     "DJ6xx",
  67.     "DJ6xxPhoto",
  68.     "DJ630",
  69.     #"DJ660", not used in HPLIP
  70.     "DJ8xx",
  71.     "DJ8x5",
  72.     "DJ850",
  73.     "DJ890",
  74.     "DJ9xx",
  75.     "DJ9xxVIP",
  76.     "DJ3600",
  77.     "DJ3320",
  78.     "DJ4100",
  79.     "AP2xxx",
  80.     "AP21xx",
  81.     "AP2560",
  82.     "PSP100",
  83.     "PSP470",
  84.     "LJZjsMono",
  85.     "LJZjsColor",
  86.     "LJm1005",
  87.     "QuickConnect",
  88.     "DJ55xx",
  89.     "OJProKx50",
  90.     'LJP1XXX',
  91.     'DJD2600',
  92. ]
  93.  
  94. TECH_CLASSES.sort()
  95.  
  96. TECH_CLASS_PDLS = {
  97.     #"Undefined"    : '?',
  98.     "Postscript"   : 'ps',
  99.     "DJGenericVIP" : 'pcl3',
  100.     #"PSB9100"      : 'pcl3',
  101.     "LJMono"       : 'pcl3',
  102.     "LJColor"      : 'pcl3',
  103.     "LJFastRaster" : 'pclxl',
  104.     "LJJetReady"   : 'pclxl',
  105.     "DJ350"        : 'pcl3',
  106.     #"DJ400"        : 'pcl3',
  107.     "DJ540"        : 'pcl3',
  108.     "DJ600"        : 'pcl3',
  109.     "DJ6xx"        : 'pcl3',
  110.     "DJ6xxPhoto"   : 'pcl3',
  111.     "DJ630"        : 'pcl3',
  112.     #"DJ660"        : 'pcl3',
  113.     "DJ8xx"        : 'pcl3',
  114.     "DJ8x5"        : 'pcl3',
  115.     "DJ850"        : 'pcl3',
  116.     "DJ890"        : 'pcl3',
  117.     "DJ9xx"        : 'pcl3',
  118.     "DJ9xxVIP"     : 'pcl3',
  119.     "DJ3600"       : 'lidil',
  120.     "DJ3320"       : 'lidil',
  121.     "DJ4100"       : 'lidil',
  122.     "AP2xxx"       : 'pcl3',
  123.     "AP21xx"       : 'pcl3',
  124.     "AP2560"       : 'pcl3',
  125.     "PSP100"       : 'pcl3',
  126.     "PSP470"       : 'pcl3',
  127.     "LJZjsMono"    : 'zjs',
  128.     "LJZjsColor"   : 'zjs',
  129.     "LJm1005"      : 'zxs',
  130.     "QuickConnect" : 'jpeg',
  131.     "DJ55xx"       : 'pcl3',
  132.     "OJProKx50"    : 'pcl3',
  133.     'LJP1XXX'      : 'zxs',
  134. }
  135.  
  136. PDL_TYPE_PCL = 0  # less preferred
  137. PDL_TYPE_PS = 1   #      /\
  138. PDL_TYPE_HOST = 2 # more preferred (however, may req. plugin)
  139.  
  140. PDL_TYPES = { # Used to prioritize PPD file selection in prnt.cups.getPPDFile2()
  141.     'pcl3' : PDL_TYPE_PCL,
  142.     'pcl5' : PDL_TYPE_PCL,
  143.     'pcl6' : PDL_TYPE_PCL,
  144.     'pcl5e' : PDL_TYPE_PCL,
  145.     'pcl' : PDL_TYPE_PCL,
  146.     'pclxl' : PDL_TYPE_PCL,
  147.     'ps' : PDL_TYPE_PS,
  148.     'lidil' : PDL_TYPE_HOST,
  149.     'zjs' : PDL_TYPE_HOST,
  150.     'zjstream' : PDL_TYPE_HOST,
  151.     'zxs' : PDL_TYPE_HOST,
  152.     'zxstream' : PDL_TYPE_HOST,
  153.     'jpeg' : PDL_TYPE_HOST,
  154.     'jpg' : PDL_TYPE_HOST,
  155.     'jetready' : PDL_TYPE_HOST,
  156.     'jr' : PDL_TYPE_HOST,
  157. }
  158.  
  159.  
  160. TECH_SUBCLASSES = [
  161.     "LargeFormatSuperB",
  162.     "LargeFormatA3",
  163.     "CoverMedia", # 3425
  164.     "FullBleed",
  165.     "Duplex",
  166.     "Normal",
  167.     "Apollo2000",
  168.     "Apollo2200",
  169.     "Apollo2500",
  170.     "NoPhotoMode",
  171.     "NoPhotoBestHiresModes",
  172.     "No1200dpiNoSensor",
  173.     "NoFullBleed",
  174.     "4x6FullBleed",
  175.     "300dpiOnly",  # LaserJet 4L
  176.     "GrayscaleOnly", # DJ540
  177.     "NoAutoTray", # PS Pro 8850
  178.     "NoEvenDuplex", # PS C8100
  179. ]
  180.  
  181. TECH_SUBCLASSES.sort()
  182.  
  183.  
  184. # Items will be capitalized unless in this dict
  185. MODEL_UI_REPLACEMENTS = {'laserjet'   : 'LaserJet',
  186.                           'psc'        : 'PSC',
  187.                           'hp'         : 'HP',
  188.                           'mfp'        : 'MFP',
  189.                         }
  190.  
  191.  
  192. def normalizeModelUIName(model):
  193.     ml = model.lower().strip()
  194.  
  195.     if 'apollo' in ml:
  196.         z = ml.replace('_', ' ')
  197.     else:
  198.         if ml.startswith("hp"):
  199.             z = ml[3:].replace('_', ' ')
  200.         else:
  201.             z = ml.replace('_', ' ')
  202.  
  203.     y = []
  204.     for x in z.split():
  205.         if pat_prod_num.search(x): # don't cap items like cp1700dn
  206.             y.append(x)
  207.         else:
  208.             y.append(MODEL_UI_REPLACEMENTS.get(x, x.capitalize()))
  209.  
  210.     if 'apollo' in ml:
  211.         return ' '.join(y)
  212.     else:
  213.         return "HP " + ' '.join(y)
  214.  
  215.  
  216. def normalizeModelName(model):
  217.     return utils.xstrip(model.replace(' ', '_').replace('__', '_').replace('~','').replace('/', '_'), '_')
  218.  
  219.  
  220. class ModelData:
  221.     def __init__(self, root_path=None):
  222.         if root_path is None:
  223.             self.root_path = prop.models_dir
  224.         else:
  225.             self.root_path = root_path
  226.  
  227.         self.__cache = {}
  228.         self.reset_includes()
  229.         self.sec = re.compile(r'^\[(.*)\]')
  230.         self.inc = re.compile(r'^\%include (.*)', re.I)
  231.         self.inc_line = re.compile(r'^\%(.*)\%')
  232.         self.eq = re.compile(r'^([^=]+)=(.*)')
  233.         self.date = re.compile(r'^(\d{1,2})/(\d{1,2})/(\d{4,4})')
  234.  
  235.         files = [(os.path.join(self.root_path, "models.dat"),
  236.                   os.path.join(self.root_path, "unreleased", "unreleased.dat")),
  237.                  (os.path.join(os.getcwd(), 'data', 'models', 'models.dat'),
  238.                   os.path.join(os.getcwd(), 'data', 'models', 'unreleased', 'unreleased.dat'))]
  239.  
  240.         for self.released_dat, self.unreleased_dat in files:
  241.             if os.path.exists(self.released_dat):
  242.                 break
  243.  
  244.         else:
  245.             self.released_dat, self.unreleased_dat = None, None
  246.             log.error("Unable to locate models.dat file")
  247.  
  248.         self.FIELD_TYPES = {
  249.             # Static model query data (from models.dat)
  250.             'align-type' : TYPE_INT,
  251.             'clean-type' : TYPE_INT,
  252.             'color-cal-type' : TYPE_INT,
  253.             'copy-type' : TYPE_INT,
  254.             'embedded-server-type' : TYPE_INT,
  255.             'fax-type' : TYPE_INT,
  256.             'fw-download' : TYPE_BOOL,
  257.             'icon' : TYPE_STR,
  258.             'io-mfp-mode' : TYPE_INT,
  259.             'io-mode' : TYPE_INT,
  260.             'io-support' : TYPE_BITFIELD,
  261.             'job-storage' : TYPE_INT,
  262.             'monitor-type' : TYPE_INT,
  263.             'linefeed-cal-type' : TYPE_INT,
  264.             'panel-check-type' : TYPE_INT,
  265.             'pcard-type' : TYPE_INT,
  266.             'plugin' : TYPE_INT,
  267.             'plugin-reason' : TYPE_BITFIELD,
  268.             'power-settings': TYPE_INT,
  269.             'pq-diag-type' : TYPE_INT,
  270.             'r-type' : TYPE_INT,
  271.             'scan-style' : TYPE_INT,
  272.             'scan-type' : TYPE_INT,
  273.             'status-battery-check' : TYPE_INT,
  274.             'status-dynamic-counters' : TYPE_INT,
  275.             'status-type' : TYPE_INT,
  276.             'support-subtype' : TYPE_HEX,
  277.             'support-released' : TYPE_BOOL,
  278.             'support-type' : TYPE_INT,
  279.             'support-ver' : TYPE_STR,
  280.             'tech-class' : TYPE_LIST,
  281.             'tech-subclass' : TYPE_LIST,
  282.             'tech-type' : TYPE_INT,
  283.             'usb-pid' : TYPE_HEX,
  284.             'usb-vid' : TYPE_HEX,
  285.             'wifi-config': TYPE_INT,
  286.             }
  287.  
  288.         self.FIELD_TYPES_DYN = {
  289.             # Dynamic model data (from device query)
  290.             'dev-file' : TYPE_STR,
  291.             'fax-uri' : TYPE_STR,
  292.             'scan-uri' : TYPE_STR,
  293.             'is-hp' : TYPE_BOOL,
  294.             'host' : TYPE_STR,
  295.             'status-desc' : TYPE_STR,
  296.             'cups-printers' : TYPE_STR,
  297.             'serial' : TYPE_STR,
  298.             'error-state' : TYPE_INT,
  299.             'device-state' : TYPE_INT,
  300.             'panel' : TYPE_INT,
  301.             'device-uri' : TYPE_STR,
  302.             'panel-line1' : TYPE_STR,
  303.             'panel-line2' : TYPE_STR,
  304.             'back-end' : TYPE_STR,
  305.             'port' : TYPE_INT,
  306.             'deviceid' : TYPE_STR,
  307.             'cups-uri' : TYPE_STR,
  308.             'status-code' : TYPE_INT,
  309.             'rs' : TYPE_STR,
  310.             'rr' : TYPE_STR,
  311.             'rg' : TYPE_STR,
  312.             'r' : TYPE_INT,
  313.             'duplexer' : TYPE_INT,
  314.             'supply-door' : TYPE_INT,
  315.             'revision' : TYPE_INT,
  316.             'media-path' : TYPE_INT,
  317.             'top-door' : TYPE_BOOL,
  318.             'photo-tray' : TYPE_BOOL,
  319.             }
  320.  
  321.         self.RE_FIELD_TYPES = {
  322.             re.compile('^r(\d+)-agent(\d+)-kind', re.IGNORECASE) : TYPE_INT,
  323.             re.compile('^r(\d+)-agent(\d+)-type', re.IGNORECASE) : TYPE_INT,
  324.             re.compile('^r(\d+)-agent(\d+)-sku', re.IGNORECASE) : TYPE_STR,
  325.             re.compile('^agent(\d+)-desc', re.IGNORECASE) : TYPE_STR,
  326.             re.compile('^agent(\d+)-virgin', re.IGNORECASE) : TYPE_BOOL,
  327.             re.compile('^agent(\d+)-dvc', re.IGNORECASE) : TYPE_INT,
  328.             re.compile('^agent(\d+)-kind', re.IGNORECASE) : TYPE_INT,
  329.             re.compile('^agent(\d+)-type', re.IGNORECASE) : TYPE_INT,
  330.             re.compile('^agent(\d+)-id', re.IGNORECASE) : TYPE_INT,
  331.             re.compile('^agent(\d+)-hp-ink', re.IGNORECASE) : TYPE_BOOL,
  332.             re.compile('^agent(\d+)-health-desc', re.IGNORECASE) : TYPE_STR,
  333.             re.compile('^agent(\d+)-health$', re.IGNORECASE) : TYPE_INT,
  334.             re.compile('^agent(\d+)-known', re.IGNORECASE) : TYPE_BOOL,
  335.             re.compile('^agent(\d+)-level', re.IGNORECASE) : TYPE_INT,
  336.             re.compile('^agent(\d+)-ack', re.IGNORECASE) : TYPE_BOOL,
  337.             re.compile('^agent(\d+)-sku', re.IGNORECASE) : TYPE_STR,
  338.             re.compile('^in-tray(\d+)', re.IGNORECASE) : TYPE_BOOL,
  339.             re.compile('^out-tray(\d+)', re.IGNORECASE) : TYPE_BOOL,
  340.             re.compile('^model(\d+)', re.IGNORECASE) : TYPE_STR,
  341.             }
  342.  
  343.         self.TYPE_CACHE = {}
  344.  
  345.  
  346.     def read_all_files(self, unreleased=True):
  347.         if os.path.exists(self.released_dat):
  348.             self.read_section(self.released_dat)
  349.  
  350.             if self.unreleased_dat is not None and os.path.exists(self.unreleased_dat):
  351.                 self.read_section(self.unreleased_dat )
  352.  
  353.         return self.__cache
  354.  
  355.  
  356.     def read_section(self, filename, section=None, is_include=False): # section==None, read all sections
  357.         found, in_section = False, False
  358.  
  359.         if section is not None:
  360.             section = section.lower()
  361.  
  362.             if is_include:
  363.                 log.debug("Searching for include [%s] in file %s" % (section, filename))
  364.             else:
  365.                 log.debug("Searching for section [%s] in file %s" % (section, filename))
  366.  
  367.         if is_include:
  368.             cache = self.__includes
  369.         else:
  370.             cache = self.__cache
  371.  
  372.         try:
  373.             fd = file(filename)
  374.         except IOError, e:
  375.             log.error("I/O Error: %s (%s)" % (filename, e.strerror))
  376.             return False
  377.  
  378.         while True:
  379.             line = fd.readline()
  380.  
  381.             if not line:
  382.                 break
  383.  
  384.             if line[0] in ('#', ';'):
  385.                 continue
  386.  
  387.             if line[0] == '[':
  388.                 if in_section and section is not None:
  389.                     break
  390.  
  391.                 match = self.sec.search(line)
  392.  
  393.                 if match is not None:
  394.                     in_section = True
  395.  
  396.                     read_section = match.group(1).lower()
  397.  
  398.                     if section is not None:
  399.                         found = in_section = (read_section == section)
  400.  
  401.                     if in_section:
  402.                         if section is not None:
  403.                             log.debug("Found section [%s] in file %s" % (read_section, filename))
  404.  
  405.                         cache[read_section] = {}
  406.  
  407.                 continue
  408.  
  409.             if line[0] == '%':
  410.                 match = self.inc.match(line)
  411.  
  412.                 if match is not None:
  413.                     inc_file = match.group(1)
  414.                     log.debug("Found include file directive: %%include %s" % inc_file)
  415.                     self.__include_files.append(os.path.join(os.path.dirname(filename), inc_file))
  416.                     continue
  417.  
  418.                 if in_section:
  419.                     match = self.inc_line.match(line)
  420.  
  421.                     if match is not None:
  422.                         inc_sect = match.group(1)
  423.                         log.debug("Found include directive %%%s%%" % inc_sect)
  424.  
  425.                         try:
  426.                             self.__includes[inc_sect]
  427.                         except KeyError:
  428.                             for inc in self.__include_files:
  429.  
  430.                                 if self.read_section(inc, inc_sect, True):
  431.                                     break
  432.                             else:
  433.                                 log.error("Include %%%s%% not found." % inc_sect)
  434.  
  435.             if in_section:
  436.                 match = self.eq.search(line)
  437.  
  438.                 if match is not None:
  439.                     key = match.group(1)
  440.                     value = match.group(2)
  441.                     value = self.convert_data(key, value)
  442.                     cache[read_section][key] = value
  443.  
  444.         fd.close()
  445.         return found
  446.  
  447.  
  448.     def reset_includes(self):
  449.         self.__include_files = []
  450.         self.__includes = {}
  451.  
  452.  
  453.     def __getitem__(self, model):
  454.         model = model.lower()
  455.  
  456.         try:
  457.             return self.__cache[model]
  458.         except:
  459.             log.debug("Cache miss: %s" % model)
  460.  
  461.             log.debug("Reading file: %s" % self.released_dat)
  462.  
  463.             if self.read_section(self.released_dat, model):
  464.                 return self.__cache[model]
  465.  
  466.             if self.unreleased_dat is not None and os.path.exists(self.unreleased_dat):
  467.                 log.debug("Reading file: %s" % self.unreleased_dat)
  468.  
  469.                 if self.read_section(self.unreleased_dat, model):
  470.                     return self.__cache[model]
  471.  
  472.             return {}
  473.  
  474.  
  475.     def all_models(self):
  476.         return self.__cache
  477.  
  478.  
  479.     def get_data_type(self, key):
  480.         try:
  481.             return self.FIELD_TYPES[key]
  482.         except KeyError:
  483.             try:
  484.                 return self.FIELD_TYPES_DYN[key]
  485.             except KeyError:
  486.                 try:
  487.                     return self.TYPE_CACHE[key]
  488.                 except KeyError:
  489.                     for pat, typ in self.RE_FIELD_TYPES.items():
  490.                         match = pat.match(key)
  491.                         if match is not None:
  492.                             self.TYPE_CACHE[key] = typ
  493.                             return typ
  494.  
  495.         log.error("get_data_type(): Field type lookup failed for key %s" % key)
  496.         return None
  497.  
  498.  
  499.     def convert_data(self, key, value, typ=None):
  500.         if typ is None:
  501.             typ = self.get_data_type(key)
  502.  
  503.         if  typ in (TYPE_BITFIELD, TYPE_INT):
  504.             try:
  505.                 value = int(value)
  506.             except (ValueError, TypeError):
  507.                 log.error("Invalid value in .dat file: %s=%s" % (key, value))
  508.                 value = 0
  509.  
  510.         elif typ == TYPE_BOOL:
  511.             value = utils.to_bool(value)
  512.  
  513.         elif typ == TYPE_LIST:
  514.             value = [x for x in value.split(',') if x]
  515.  
  516.         elif typ == TYPE_DATE: # mm/dd/yyyy
  517.             if datetime_avail:
  518.                 # ...don't use datetime.strptime(), wasn't avail. until 2.5
  519.                 match = self.date.search(value)
  520.  
  521.                 if match is not None:
  522.                     month = int(match.group(1))
  523.                     day = int(match.group(2))
  524.                     year = int(match.group(3))
  525.  
  526.                     value = datetime.date(year, month, day)
  527.  
  528.         elif typ == TYPE_HEX:
  529.             try:
  530.                 value = int(value, 16)
  531.             except (ValueError, TypeError):
  532.                 log.error("Invalid hex value in .dat file: %s=%s" % (key, value))
  533.                 value = 0
  534.  
  535.         return value
  536.